package com.yanqu.road.server.manager.zhaoshang;

import com.yanqu.road.entity.rank.cross.CrossUserRank;
import com.yanqu.road.entity.servercenter.CrossServerGroup;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.bussiness.rank.RankBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.cross.CrossGroupWeekRankListModel;
import com.yanqu.road.pb.common.CommonProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manger.CrossServerGroupMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.plugin.ManagerReloadListener;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.date.DateHelper;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ZsRankMgr extends TempMgr {

    // groupId weekId bigType type
    private static Map<Integer, Map<Integer, Map<Integer, Map<Integer, CrossGroupWeekRankListModel>>>> groupWeekRankListModelMap;

    @Override
    public boolean reloadData() throws Exception {
        groupWeekRankListModelMap = new ConcurrentHashMap<>();
        initCrossRankListModelMap();
        return true;
    }

    @Override
    public boolean init() throws Exception {
        addServerGroupReloadListener();
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean save() {

        for(int groupId : groupWeekRankListModelMap.keySet()){
            Map<Integer, Map<Integer, Map<Integer, CrossGroupWeekRankListModel>>> weekMap = groupWeekRankListModelMap.get(groupId);
            for(int weekId : weekMap.keySet()){
                Map<Integer, Map<Integer, CrossGroupWeekRankListModel>> bigTypeMap = weekMap.get(weekId);
                if(bigTypeMap == null){
                    continue;
                }
                for(int bigType : bigTypeMap.keySet()){
                    Map<Integer, CrossGroupWeekRankListModel> typeMap = bigTypeMap.get(bigType);
                    for(Map.Entry<Integer, CrossGroupWeekRankListModel> dataEntry : typeMap.entrySet()){
                        dataEntry.getValue().saveRankList();
                    }
                }
            }
        }

        return true;
    }

    private void addServerGroupReloadListener(){
        CrossServerGroupMgr.addReloadListener(new ManagerReloadListener() {
            @Override
            public void notifyReload() {
                try {
                    ServerListMgr.reloadServerList();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                serverGroupReload();
                notifyServerReload();
            }
        });
    }

    private void initCrossRankListModelMap() {

        Calendar now = Calendar.getInstance();
        Date monday = DateHelper.getThisWeekMonday(now.getTime());
        now.setTime(monday);
        int thisWeekId = Integer.valueOf(DateHelper.getPyyyyMMddDateString(now.getTimeInMillis() / 1000));
        now.add(Calendar.HOUR, -7 * 24);
        int preWeekId = Integer.valueOf(DateHelper.getPyyyyMMddDateString(now.getTimeInMillis() / 1000));
        Map<Integer, Map<Integer, Map<Integer, Map<Integer, LinkedList<CrossUserRank>>>>> tempDbMap = RankBussiness.getCrossGroupWeekRankListMap(preWeekId,thisWeekId);
        synchronized (groupWeekRankListModelMap) {
            for (Map.Entry<Integer, Map<Integer, Map<Integer, Map<Integer, LinkedList<CrossUserRank>>>>> groupEntry : tempDbMap.entrySet()) {
                for (Map.Entry<Integer, Map<Integer, Map<Integer, LinkedList<CrossUserRank>>>> weekEntry : groupEntry.getValue().entrySet()) {
                    for (Map.Entry<Integer, Map<Integer, LinkedList<CrossUserRank>>> bigTypeEntry : weekEntry.getValue().entrySet()) {
                        for (Map.Entry<Integer, LinkedList<CrossUserRank>> typeEntry : bigTypeEntry.getValue().entrySet()) {
                            CrossGroupWeekRankListModel listModel = new CrossGroupWeekRankListModel(groupEntry.getKey(), weekEntry.getKey(), bigTypeEntry.getKey(), typeEntry.getKey());

                            listModel.setRankNum(GameConfig.RANK_DEFAULT_MAX_COUNT);
                            listModel.setRankList(typeEntry.getValue());

                            if (!groupWeekRankListModelMap.containsKey(groupEntry.getKey())) {
                                groupWeekRankListModelMap.put(groupEntry.getKey(), new ConcurrentHashMap<>());
                            }

                            if (!groupWeekRankListModelMap.get(groupEntry.getKey()).containsKey(weekEntry.getKey())) {
                                groupWeekRankListModelMap.get(groupEntry.getKey()).put(weekEntry.getKey(), new ConcurrentHashMap<>());
                            }

                            if (!groupWeekRankListModelMap.get(groupEntry.getKey()).get(weekEntry.getKey()).containsKey(bigTypeEntry.getKey())) {
                                groupWeekRankListModelMap.get(groupEntry.getKey()).get(weekEntry.getKey()).put(bigTypeEntry.getKey(), new ConcurrentHashMap<>());
                            }
                            groupWeekRankListModelMap.get(groupEntry.getKey()).get(weekEntry.getKey()).get(bigTypeEntry.getKey()).put(typeEntry.getKey(), listModel);
                        }
                    }
                }
            }
        }
    }

    public static void changeUserRank(int groupId, int weekId, int bigType, int type, CrossUserRank crossUserRank){
        CrossGroupWeekRankListModel rankListModel = getCrossGroupWeekRankListModel(groupId, weekId, bigType, type);
        if (null == rankListModel) {
            synchronized (groupWeekRankListModelMap) {
                rankListModel = getCrossGroupWeekRankListModel(groupId, weekId, bigType, type);
                if(null == rankListModel) {
                    if (!groupWeekRankListModelMap.containsKey(groupId)) {
                        groupWeekRankListModelMap.put(groupId, new ConcurrentHashMap<>());
                    }

                    if (!groupWeekRankListModelMap.get(groupId).containsKey(weekId)) {
                        groupWeekRankListModelMap.get(groupId).put(weekId, new ConcurrentHashMap<>());
                    }

                    if (!groupWeekRankListModelMap.get(groupId).get(weekId).containsKey(bigType)){
                        groupWeekRankListModelMap.get(groupId).get(weekId).put(bigType, new ConcurrentHashMap<>());
                    }
                    if (!groupWeekRankListModelMap.get(groupId).get(weekId).get(bigType).containsKey(type)) {
                        rankListModel = new CrossGroupWeekRankListModel(groupId, weekId, bigType, type);
                        rankListModel.setRankNum(GameConfig.RANK_DEFAULT_MAX_COUNT);
                        groupWeekRankListModelMap.get(groupId).get(weekId).get(bigType).put(type, rankListModel);
                    }
                }
            }
            rankListModel = getCrossGroupWeekRankListModel(groupId, weekId, bigType, type);
        }
        if (null != rankListModel) {
            rankListModel.rankChange(crossUserRank);
        }
    }

    public static CrossGroupWeekRankListModel getCrossGroupWeekRankListModel(int groupId, int weekId, int bigType, int type) {
        Map<Integer, CrossGroupWeekRankListModel> groupWeekBigTypeMap = getCrossGroupWeekRankListModel(groupId, weekId, bigType);
        if(groupWeekBigTypeMap == null){
            return null;
        }
        CrossGroupWeekRankListModel rankListModel = groupWeekBigTypeMap.get(type);
        return rankListModel;
    }

    public static Map<Integer, CrossGroupWeekRankListModel> getCrossGroupWeekRankListModel(int groupId, int weekId, int bigType) {
        Map<Integer, Map<Integer, Map<Integer, CrossGroupWeekRankListModel>>> groupMap = groupWeekRankListModelMap.get(groupId);
        if(groupMap == null){
            return null;
        }
        Map<Integer, Map<Integer, CrossGroupWeekRankListModel>> groupWeekMap = groupMap.get(weekId);
        if(groupWeekMap == null){
            return null;
        }

        Map<Integer, CrossGroupWeekRankListModel> groupWeekBigTypeMap = groupWeekMap.get(bigType);
        return groupWeekBigTypeMap;
    }

    public static int getGroupId(long serverId) {
        CrossServerGroup serverGroup = CrossServerGroupMgr.getServerGroupByServerId(serverId);
        if(serverGroup != null && serverGroup.getCrossZsState() == 1){
            return serverGroup.getGroupId();
        }
        return (int)serverId;
    }

    public static void serverGroupReload() {
        //区服重载，排行榜重新分组
        int thisWeekId = getThisWeekId();
        LinkedList<CrossUserRank> crossUserRanks = new LinkedList<>();
        synchronized (groupWeekRankListModelMap) {
            for (int groupId : groupWeekRankListModelMap.keySet()) {
                Map<Integer, Map<Integer, Map<Integer, CrossGroupWeekRankListModel>>> weekMap = groupWeekRankListModelMap.get(groupId);
                Set<Long> serverIdSet = getGroupServer(groupId);
                for (int weekId : weekMap.keySet()) {
                    if (weekId != thisWeekId) {
                        continue;
                    }
                    Map<Integer, Map<Integer, CrossGroupWeekRankListModel>> bigTypeMap = weekMap.get(weekId);
                    for (int bigType : bigTypeMap.keySet()) {
                        Map<Integer, CrossGroupWeekRankListModel> typeMap = bigTypeMap.get(bigType);
                        for (Map.Entry<Integer, CrossGroupWeekRankListModel> dataEntry : typeMap.entrySet()) {
                            if(serverIdSet.contains((long)groupId) && getGroupId((long)groupId) != groupId){  //本服->跨服
                                crossUserRanks.addAll(dataEntry.getValue().removeRank(new HashSet<>()));
                            }else {  //区服范围变更
                                crossUserRanks.addAll(dataEntry.getValue().removeRank(serverIdSet));
                            }
                        }
                    }
                }
            }
        }
        for(CrossUserRank userRank : crossUserRanks){
            int groupId = getGroupId(userRank.getUserBaseInfo().getServerId());
            changeUserRank(groupId, thisWeekId, userRank.getBigRankType(), userRank.getType(), userRank);
        }
    }

    //本周id
    public static int getThisWeekId(){
        Calendar now = Calendar.getInstance();
        Date monday = DateHelper.getThisWeekMonday(now.getTime());
        now.setTime(monday);
        return Integer.valueOf(DateHelper.getPyyyyMMddDateString(now.getTimeInMillis() / 1000));
    }

    //获取所在组的区服列表(没有分组即独自成组)
    public static Set<Long> getGroupServer(int groupId){
        Set<Long> serverSet = new HashSet<>();
        CrossServerGroup serverGroup = CrossServerGroupMgr.getServerGroup(groupId);
        if(serverGroup == null || serverGroup.getCrossZsState() == 0){
            serverSet.add((long)groupId);
        }else{
            serverSet.addAll(serverGroup.getServerList());
        }
        return serverSet;
    }

    private static void notifyServerReload(){
        List<ServerInfo> serverInfoList = ServerListMgr.getOpenServerList();
        int channelId = ConfigHelper.getInt("channelId");
        CommonProto.NullValueMsg.Builder msg = CommonProto.NullValueMsg.newBuilder();
        YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.S_CROSS_SERVER_GROUP_RELOAD_NOTIFY_NEW, msg);
        for(ServerInfo serverInfo : serverInfoList){
            if(serverInfo.getChannelId() == channelId){
                MessageHelper.sendPacket(serverInfo.getServerId(), 0, pbMsg);
            }
        }
    }

    //过期数据移除
    public static void removeOutTimeData(){
        Calendar now = Calendar.getInstance();
        now.add(Calendar.MONTH, -1);
        int monthBefore = Integer.valueOf(DateHelper.getPyyyyMMddDateString(now.getTimeInMillis() / 1000));
        for(int groupId : groupWeekRankListModelMap.keySet()){
            Map<Integer, Map<Integer, Map<Integer, CrossGroupWeekRankListModel>>> weekMap = groupWeekRankListModelMap.get(groupId);
            for(int weekId : weekMap.keySet()){
                if(weekId < monthBefore){
                    synchronized (groupWeekRankListModelMap){
                        weekMap.remove(weekId);
                    }
                }
            }
        }
    }

}
